// app.js
// 引入 toast 模块
const toast = require("./companies/toast.js").default;
import config from "./config/config";

App({
  globalData: {
    isLoggedIn: false,
    socket: null,
    subscribeMap: {}, // 订阅者映射表
    reconnectAttempts: 0,
    maxReconnectAttempts: 3,
    heartbeatTimer: null, // 心跳定时器
    reconnectTimer: null, // 重连定时器
    currentPage: "index",
  },

  // 使用引入的 showToast 方法
  showToast: toast.showToast,

  /**
   * 小程序初始化
   */
  onLaunch: function () {
    const token = wx.getStorageSync("token");
    const user = wx.getStorageSync("userInfo");

    // 1. 检查 token 是否有效
    if (!this.checkTokenValid(token)) {
      console.error("Token 无效或已过期");
      wx.reLaunch({ url: "/pages/login/login" });
      return;
    }

    // 2. 检查用户信息是否完整
    if (!user || !user.id || user.id === "undefined") {
      console.error("用户信息不完整或无效");
      wx.reLaunch({ url: "/pages/login/login" });
      return;
    }

    // 3. 初始化 WebSocket 连接
    const url = `ws://${config.ip}/choose-websocket?userId=${encodeURIComponent(user.id)}`;
    this.initWebsocket(url);

    // 4. 拦截页面跳转（检查登录状态）
    this.interceptPageNavigation();
  },

  /**
   * 检查 Token 是否有效
   */
  checkTokenValid: function (token) {
    if (!token || !token.token || !token.tokenTimeout) {
      return false;
    }
    const currentTime = new Date().getTime();
    const tokenExpireTime = new Date(token.tokenTimeout).getTime();
    return currentTime < tokenExpireTime;
  },

  /**
   * 初始化 WebSocket 连接
   */
  initWebsocket(url) {
    const { socket } = this.globalData;
    const user = wx.getStorageSync("userInfo");

    // 1. 检查用户信息是否仍然有效
    if (!user || !user.id || user.id === "undefined") {
      console.error("无法建立 WebSocket：用户信息无效");
      toast.showToast("用户信息异常，请重新登录", "error");
      wx.reLaunch({ url: "/pages/login/login" });
      return;
    }

    // 2. 避免重复连接
    if (socket) {
      console.log("WebSocket 已连接，无需重复初始化");
      return;
    }

    // 3. 建立 WebSocket 连接
    this.globalData.socket = wx.connectSocket({
      url: url,
      fail: (err) => {
        console.error("WebSocket 连接失败", err);
        this.reconnect(url); // 失败后尝试重连
      },
    });

    // 4. 监听 WebSocket 事件
    wx.onSocketOpen(() => {
      console.log("WebSocket 连接成功");
      this.startHeartbeat(); // 开启心跳检测
      this.globalData.reconnectAttempts = 0; // 重置重连次数
    });

    wx.onSocketError((err) => {
      console.error("WebSocket 连接错误", err);
      this.stopHeartbeat();
      this.globalData.socket = null;
      this.reconnect(url); // 出错后尝试重连
    });

    wx.onSocketMessage((res) => {
      console.log("收到 WebSocket 消息", res.data);
      this.notifySubscribers(res.data); // 通知订阅者
    });

    wx.onSocketClose(() => {
      console.log("WebSocket 连接关闭");
      this.stopHeartbeat();
      this.globalData.socket = null;
      this.reconnect(url); // 连接关闭后尝试重连
    });
  },

  /**
   * 发送消息
   */
  sendMessage(data, successCallback, failCallback) {
    const { socket } = this.globalData;
    if (!socket) {
      console.error("WebSocket 未连接");
      failCallback && failCallback("WebSocket 未连接");
      return;
    }

    wx.sendSocketMessage({
      data: data,
      success: () => {
        console.log("消息发送成功");
        successCallback && successCallback();
      },
      fail: (err) => {
        console.error("消息发送失败", err);
        failCallback && failCallback(err);
      },
    });
  },

  /**
   * 订阅消息
   */
  subscribe(eventName, callback) {
    const { subscribeMap } = this.globalData;
    if (!subscribeMap[eventName]) {
      subscribeMap[eventName] = [];
    }
    subscribeMap[eventName].push(callback);
  },

  /**
   * 取消订阅
   */
  unsubscribe(eventName, callback) {
    const { subscribeMap } = this.globalData;
    if (subscribeMap[eventName]) {
      subscribeMap[eventName] = subscribeMap[eventName].filter(
        (cb) => cb !== callback
      );
    }
  },

  /**
   * 通知订阅者
   */
  notifySubscribers(data) {
    const { subscribeMap } = this.globalData;
    try {
      const parsedData = JSON.parse(data);
      const messageType = parsedData.messageType;
      if (subscribeMap[messageType]) {
        subscribeMap[messageType].forEach((callback) => {
          callback(data);
        });
      }
    } catch (e) {
      console.error("解析消息失败", e);
    }
  },

  /**
   * 关闭 WebSocket 连接
   */
  closeWebsocket() {
    const { socket } = this.globalData;
    if (socket) {
      this.stopHeartbeat();
      wx.closeSocket();
      this.globalData.socket = null;
    }
  },

  /**
   * 拦截页面跳转（检查登录状态）
   */
  interceptPageNavigation() {
    const originalNavigateTo = wx.navigateTo;
    const originalRedirectTo = wx.redirectTo;
    const originalReLaunch = wx.reLaunch;
    const originalSwitchTab = wx.switchTab;

    wx.navigateTo = function (options) {
      if (this.shouldIntercept(options.url)) {
        console.log("拦截 navigateTo:", options.url);
        return;
      }
      originalNavigateTo.call(this, options);
    }.bind(this);

    wx.redirectTo = function (options) {
      if (this.shouldIntercept(options.url)) {
        console.log("拦截 redirectTo:", options.url);
        return;
      }
      originalRedirectTo.call(this, options);
    }.bind(this);

    wx.reLaunch = function (options) {
      if (this.shouldIntercept(options.url)) {
        console.log("拦截 reLaunch:", options.url);
        return;
      }
      originalReLaunch.call(this, options);
    }.bind(this);

    wx.switchTab = function (options) {
      if (this.shouldIntercept(options.url)) {
        console.log("拦截 switchTab:", options.url);
        return;
      }
      originalSwitchTab.call(this, options);
    }.bind(this);
  },

  /**
   * 判断是否需要拦截页面跳转
   */
  shouldIntercept(url) {
    const token = wx.getStorageSync("token");
    const user = wx.getStorageSync("userInfo");

    // 1. 检查 token 是否有效
    if (!this.checkTokenValid(token)) {
      console.log("Token 无效或已过期");
      this.globalData.isLoggedIn = false;
      wx.removeStorageSync("token");
      wx.removeStorageSync("userInfo");
    } else {
      this.globalData.isLoggedIn = true;
    }

    // 2. 检查用户信息是否完整
    if (!user || !user.id || user.id === "undefined") {
      console.log("用户信息不完整");
      this.globalData.isLoggedIn = false;
    }

    // 3. 未登录且目标页面不是登录页，则拦截
    if (!this.globalData.isLoggedIn && !url.startsWith("/pages/login")) {
      toast.showToast("请先登录", "info");
      wx.reLaunch({ url: "/pages/login/login" });
      return true;
    }

    return false;
  },

  /**
   * 开启心跳检测
   */
  startHeartbeat() {
    this.stopHeartbeat(); // 先停止之前的心跳
    this.globalData.heartbeatTimer = setInterval(() => {
      this.sendMessage(
        JSON.stringify({ messageType: "heartbeat" }),
        () => console.log("心跳发送成功"),
        (err) => {
          console.error("心跳发送失败", err);
          this.closeWebsocket();
        }
      );
    }, 30000); // 30秒一次心跳
  },

  /**
   * 停止心跳检测
   */
  stopHeartbeat() {
    if (this.globalData.heartbeatTimer) {
      clearInterval(this.globalData.heartbeatTimer);
      this.globalData.heartbeatTimer = null;
    }
  },

  /**
   * 重连机制
   */
  reconnect(url) {
    const { reconnectAttempts, maxReconnectAttempts } = this.globalData;

    // 1. 检查用户信息是否仍然有效
    const user = wx.getStorageSync("userInfo");
    if (!user || !user.id || user.id === "undefined") {
      console.log("取消重连：用户信息无效");
      return;
    }

    // 2. 清除之前的重连定时器
    if (this.globalData.reconnectTimer) {
      clearTimeout(this.globalData.reconnectTimer);
    }

    // 3. 判断是否达到最大重连次数
    if (reconnectAttempts < maxReconnectAttempts) {
      console.log(`尝试第 ${reconnectAttempts + 1} 次重连`);
      this.globalData.reconnectTimer = setTimeout(() => {
        this.globalData.reconnectAttempts++;
        this.initWebsocket(url);
      }, 3000); // 3秒后重试
    } else {
      console.log("已达最大重连次数，停止重连");
      toast.showToast("网络连接失败，请检查网络", "error");
      this.globalData.reconnectAttempts = 0; // 重置计数器
    }
  },
});